home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************/
-
-
- #include "SpeechRecognition.h"
- #include "GestaltEqu.h"
- #include "Quickdraw.h"
- #include "Dialogs.h"
- #include "Fonts.h"
- #include "AppleEvents.h"
- #include "string.h"
- #include "Speech.h"
- #include <Packages.h>
-
- #include "SpeakableItems.h"
-
- // Comment following out, and set SIZE background-only bit to make faceless version
- #define __HAS_UI__
-
- //#define __USE_CALLBACKS__
-
- /*****************************************************************************/
-
- /* Prototypes and globals */
-
- OSErr InitStuff (void);
- OSErr InitAndStartSpeechRecognition (void);
- void MainLoop (void);
- void SayDateOrTime (Boolean date);
- #ifdef __HAS_UI__
- void HandleMouseDown (EventRecord *theEvent);
- void HandleUpdate (EventRecord *theEvent);
- void HandleMenuSelect (long menuChoice);
- #endif
- void CleanupStuff (void);
- void CleanupSpeechRecognitionStuff (void);
- OSErr MakeALanguageModel (SRLanguageModel *lm);
- pascal OSErr HandleQuitAE (AppleEvent *theAEevt, AppleEvent* reply, long refcon);
- pascal OSErr DummyAEHandler (AppleEvent *theAEevt, AppleEvent* reply, long refcon);
- void ProcessResult (OSErr origStatus, SRRecognitionResult recResult);
- #ifdef __USE_CALLBACKS__
- pascal void MyNotificationCallBack (SRCallBackStruct *param);
- #else
- pascal OSErr HandleSpeechDoneAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon);
- pascal OSErr HandleSpeechBeginningAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon);
- #endif
-
- #ifdef __HAS_UI__
- void DisplayString (Str255 str);
- #endif
-
- #ifdef __HAS_UI__
- #define kAppleMenu 1
- #define kFileMenu 2
- #define kFirstMenu kAppleMenu
- #define kLastMenu kFileMenu
-
- DialogPtr gDialog;
- MenuHandle gMenuHandles[kLastMenu];
- #endif
-
- SRRecognitionSystem gSystem = 0;
- SRRecognizer gRecognizer = 0;
- SRLanguageModel gTopLM = 0;
- SRLanguageModel gSIModel = 0; /* For SpeakableItems */
- Boolean gFinished;
- Str255 gLastStr;
- SRCallBackStruct gCallBackInfo;
-
- #define kTopLMRefCon 10000
- #define kQuitSpeakableItems 10002
- #define kWhatTimeIsIt 10004
- #define kWhatDayIsIt 10006
-
- #define kSimpleStrsID 500
- #define kQuitStr 1
- #define kWhatTimeIsItStr 2
- #define kWhatDayIsItStr 3
-
- /*****************************************************************************/
-
- void main (void)
- {
- OSErr status = InitStuff ();
- if (!status) {
- MainLoop ();
- CleanupStuff ();
- }
- }
-
- /*****************************************************************************/
-
- /* main is the entry point to his program. */
-
- OSErr InitStuff (void)
- {
- OSErr status = noErr;
- Rect rBounds;
- GrafPtr oldPort;
- SRLanguageObjectFlags autoFin = kSRNoFinishing;
- MenuHandle menuH;
- short i;
-
- /* Adjust heap */
- #ifdef __HAS_UI__
- MaxApplZone();
- MoreMasters();
- MoreMasters();
- #endif
-
- /* Init toolboxes */
- InitGraf(&qd.thePort);
- #ifdef __HAS_UI__
- InitFonts();
- FlushEvents(everyEvent,0);
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(0);
- InitCursor();
- #endif
-
- #ifdef __HAS_UI__
- for (i = kFirstMenu; i <= kLastMenu; i++) {
- menuH = GetMenu(i);
- gMenuHandles[i-1] = menuH;
- if (menuH) InsertMenu (menuH, 0);
- }
- menuH = gMenuHandles[kAppleMenu-1];
- if (menuH) AddResMenu(menuH,'DRVR');
- DrawMenuBar();
-
-
- /* Make a dialog in which we'll display results */
- SetRect (&rBounds, 50,50,450,150);
- gDialog = NewDialog(NULL,&rBounds,"\p",true,noGrowDocProc,(WindowPtr)-1,true,0,NULL);
- if (!gDialog)
- status = -1;
- #endif
-
- if (!status)
- status = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
- NewAEEventHandlerProc (DummyAEHandler), 0, false);
- if (!status)
- status = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
- NewAEEventHandlerProc (DummyAEHandler), 0, false);
- if (!status)
- status = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
- NewAEEventHandlerProc (DummyAEHandler), 0, false);
- if (!status)
- status = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
- NewAEEventHandlerProc (HandleQuitAE), 0, false);
-
- if (!status)
- status = InitAndStartSpeechRecognition ();
-
-
- if (!status)
- gFinished = false;
- else
- gFinished = true;
-
- }
-
- /*****************************************************************************/
-
- /* This routine initializes speech recognition, installs an AppleEvent handler
- to handle result notifications from the Speech Recognition Toolbox, calls
- another routine to build a simple language model (which specifies a few
- phrases a user can say), makes that language model active by calling
- SRSetLanguageModel, and starts the recognizer listening. A more realistic
- application would have more complicated language models (perhaps having
- different language models for different contexts -- using SRSetLanguageModel
- to make the appropriate one active), or would use the language model
- manipulation routines in the Speech Recognition Toolbox to change the
- active language model as the program was used to reflect what the user
- might say in any given situation.
- */
-
- OSErr InitAndStartSpeechRecognition ()
- {
- OSErr status;
- long attributes;
- Boolean fgOnly = false;
- SRCallBackParam callBackPB;
- long notifFlags = kSRNotifyRecognitionBeginning | kSRNotifyRecognitionDone;
-
- #ifdef __HAS_UI__
- /* The SROpenRecognitionSystem loads lots of data and takes a few
- seconds, so display a message indicating this will take a moment.
- This would be a good place to show the watch cursor as well. */
- DisplayString ("\pStarting up...");
- #endif
- /* Make sure SpeechRecognition Toolbox is available */
- status = Gestalt (gestaltSpeechRecognitionVersion, &attributes);
-
- /* Open a SRRecognitionSystem */
- if (!status)
- status = SROpenRecognitionSystem (&gSystem, kSRDefaultRecognitionSystemID);
-
- /* Create a recognizer with default speech source -- e.g. the desktop microphone */
- if (!status)
- status = SRNewRecognizer (gSystem, &gRecognizer, kSRDefaultSpeechSource);
-
- if (!status)
- status = SRSetProperty (gRecognizer, kSRForegroundOnly, &fgOnly, sizeof(fgOnly));
- if (!status)
- status = SRSetProperty (gRecognizer, kSRNotificationParam, ¬ifFlags, sizeof(notifFlags));
-
- #ifdef __USE_CALLBACKS__
- /* Install call-back */
- if (!status) {
- callBackPB.callBack = NewSRCallBackProc (MyNotificationCallBack);
- callBackPB.param = &gCallBackInfo;
- status = SRSetProperty (gRecognizer, kSRCallBackParam, &callBackPB, sizeof (callBackPB));
- }
- #else
- /* Install an AppleEvent handler so recognizer can send us recognition results. */
- if (!status)
- status = AEInstallEventHandler(kAESpeechSuite, kAESpeechDone,
- NewAEEventHandlerProc (HandleSpeechDoneAppleEvent), 0, false);
- if (!status)
- status = AEInstallEventHandler(kAESpeechSuite, kAESpeechDetected,
- NewAEEventHandlerProc (HandleSpeechBeginningAppleEvent), 0, false);
- #endif
-
- /* For this example, we will just make one language model,
- make it active, and start listening. */
-
- /* Make a simple language model (LM) */
- if (!status)
- status = MakeALanguageModel (&gTopLM);
-
- /* Use this LM in recognition */
- if (!status)
- status = SRSetLanguageModel (gRecognizer, gTopLM);
-
- /* Have the recognizer start processing sound */
- if (!status)
- status = SRStartListening (gRecognizer);
-
- /* Initialize Speakable Items unit and get an LM representing
- the speakable items, and add it to our top level LM. */
-
- if (!status)
- status = SIInitSpeakableItems (gSystem, &gSIModel);
-
- if (!status && gSIModel)
- status = SRAddLanguageObject (gTopLM, gSIModel);
-
- #ifdef __HAS_UI__
- if (!status)
- DisplayString ("\pReady");
- else
- // Couldn't run for some reason. Perhaps there is no 'Speakable Items' folder in the 'Apple Menu Items' folder,
- // or perhaps Speech Recognition extension is not installed.
- DisplayString ("\pSorry, Can't run. See trouble shooting notes.");
- #endif
-
- return status;
- }
-
-
- /*****************************************************************************/
-
- void MainLoop ()
- {
- Boolean gotEvent;
- EventRecord event;
- DialogPtr theDialog;
- short itemHit;
- long sleepTime;
- char ch;
-
- /* Here's our overly-simple main event loop */
- /* We quit if mouse is clicked in window, */
- /* or if any key is clicked. */
- /* We also dispatch AppleEvents. */
- while (!gFinished) {
- if (gFinished) sleepTime = 1; else sleepTime = 0xFFFFFFFF;
- gotEvent = WaitNextEvent(everyEvent, &event, sleepTime, NULL);
- if (gotEvent) {
- switch (event.what) {
- #ifdef __HAS_UI__
- case mouseDown :
- HandleMouseDown (&event);
- break;
- case keyDown :
- ch = event.message & charCodeMask;
- if (event.modifiers & cmdKey)
- HandleMenuSelect (MenuKey(ch));
- break;
- case updateEvt :
- HandleUpdate (&event);
- break;
- #endif
- case kHighLevelEvent :
- AEProcessAppleEvent(&event);
- break;
- default :
- break;
- }
- }
- #ifdef __HAS_UI__
- if (IsDialogEvent(&event))
- DialogSelect(&event, &theDialog, &itemHit);
- #endif
- if (!gFinished)
- SIUpdateSpeakableItems (gSystem, gSIModel);
- }
- }
-
- /*****************************************************************************/
-
- #ifdef __HAS_UI__
- void HandleMouseDown (EventRecord *theEvent)
- {
- WindowPtr theWindow;
- short inWhatPart = FindWindow (theEvent->where, &theWindow);
- Point pt = theEvent->where;
- GrafPtr oldPort;
- Rect rct;
-
- switch (inWhatPart) {
- case inSysWindow :
- SystemClick (theEvent, theWindow);
- break;
- case inContent:
- break;
- case inMenuBar :
- HandleMenuSelect (MenuSelect(theEvent->where));
- break;
- case inDrag :
- rct = qd.screenBits.bounds;
- InsetRect (&rct, 20, 20);
- DragWindow (theWindow, pt, &rct);
- break;
- case inGoAway:
- if (TrackGoAway (theWindow, pt))
- gFinished = true;
- break;
- default :
- break;
- }
- HiliteMenu (0);
- }
- #endif
-
- /*****************************************************************************/
-
- #ifdef __HAS_UI__
- void HandleUpdate (EventRecord *theEvent)
- {
- DisplayString (gLastStr);
- }
- #endif
-
- /*****************************************************************************/
-
- #ifdef __HAS_UI__
- void HandleMenuSelect (long menuChoice)
- {
- short itemNum;
- Str255 daName;
- GrafPtr ourPort;
-
- itemNum = LoWord(menuChoice);
- switch (HiWord(menuChoice)) {
- case kAppleMenu :
- GetItem (gMenuHandles[kAppleMenu-1], itemNum, daName);
- GetPort (&ourPort);
- OpenDeskAcc (daName);
- SetPort (ourPort);
- break;
- case kFileMenu :
- // all we've got is quit
- gFinished = true;
- break;
- default :
- break;
- }
- }
- #endif
-
- /*****************************************************************************/
-
- void CleanupStuff ()
- {
- CleanupSpeechRecognitionStuff ();
-
- #ifdef __HAS_UI__
- if (gDialog)
- DisposeDialog (gDialog);
- #endif
- }
-
- /*****************************************************************************/
-
- void CleanupSpeechRecognitionStuff ()
- {
- OSErr status;
-
- if (gTopLM)
- status = SRReleaseObject (gTopLM);
- if (gSIModel)
- status = SRReleaseObject (gSIModel);
- if (gRecognizer) {
- status = SRStopListening (gRecognizer); /* stop processing incoming sound */
- status = SRReleaseObject (gRecognizer); /* balance SRNewRecognizer call */
- }
- if (gSystem)
- status = SRCloseRecognitionSystem (gSystem); /* balance SROpenRecognitionSystem call */
- }
-
- /*****************************************************************************/
-
- OSErr MakeALanguageModel (SRLanguageModel *model)
- {
- const char *lmName = "<Sample LM>";
- long refCon = kTopLMRefCon;
- Str255 str;
- OSErr status;
- SRLanguageModel newModel;
-
-
- /* make a simple language model (LM) */
- status = SRNewLanguageModel (gSystem, &newModel, lmName, strlen (lmName));
-
- /* set its refcon */
- if (!status)
- status = SRSetProperty (newModel, kSRRefCon, &refCon, sizeof(refCon));
-
- /* add some items to the top level LM */
- if (!status) {
- GetIndString(str, kSimpleStrsID, kQuitStr);
- status = SRAddText (newModel, str+1, str[0], kQuitSpeakableItems);
- GetIndString(str, kSimpleStrsID, kWhatTimeIsItStr);
- status = SRAddText (newModel, str+1, str[0], kWhatTimeIsIt);
- GetIndString(str, kSimpleStrsID, kWhatDayIsItStr);
- status = SRAddText (newModel, str+1, str[0], kWhatDayIsIt);
- }
-
- /* return new LM */
- if (!status)
- *model = newModel;
-
- return status;
- }
-
- /*****************************************************************************/
- /*****************************************************************************/
-
- pascal OSErr DummyAEHandler (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
- {
- return noErr;
- }
-
- /*****************************************************************************/
-
- pascal OSErr HandleQuitAE (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
- {
- gFinished = true;
- return noErr;
-
- }
-
- /*****************************************************************************/
-
- #ifdef __USE_CALLBACKS__
- pascal void MyNotificationCallBack (SRCallBackStruct *param)
- {
- OSErr status = param->status;
- SRRecognitionResult recResult = 0;
-
- // Handle speech-done
- if (param->what & kSRNotifyRecognitionDone) {
- if (!status)
- recResult = (SRRecognitionResult)(param->message);
- ProcessResult (status, recResult);
- }
- }
-
- #else
-
- /*****************************************************************************/
-
- /* Here's an AppleEvent handler for handling the kAESpeechDone event of the
- kAESpeechSuite -- i.e. the event indicating a recognition attempt was made.
- The keySRSpeechStatus parameter gives the status of the recognition. If it
- is noErr, then the keySRSpeechResult parameter gives a SRRecognitionResult with the
- various representations of the words the user spoke.
- */
-
- pascal OSErr HandleSpeechDoneAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
- {
- long actualSize;
- DescType actualType;
- OSErr status = 0;
- OSErr recStatus = 0;
- SRRecognitionResult recResult = 0;
-
- /* Get status */
- status = AEGetParamPtr(theAEevt,keySRSpeechStatus,typeShortInteger,
- &actualType, (Ptr)&recStatus, sizeof(status), &actualSize);
-
- /* Get result */
- if (!status && !recStatus)
- status = AEGetParamPtr(theAEevt,keySRSpeechResult,typeSRSpeechResult,
- &actualType, (Ptr)&recResult, sizeof(SRRecognitionResult), &actualSize);
-
- /* Process result */
- if (!status)
- status = recStatus;
- ProcessResult (status, recResult);
-
- return status;
- }
-
- /*****************************************************************************/
-
- /* AppleEvent handler for kAESpeechDetected event of kAESpeechSuite -- the
- event indicating that recognition of an utterance is ready to begin. We
- are sent this event because we requested kSRNotifyRecognitionBeginning notification
- as well as kSRNotifyRecognitionDone notification. (See InitAndStartSpeechRecognition
- routine above, where we set the kSRNotificationParam property of our SRRecognizer.)
- */
-
- pascal OSErr HandleSpeechBeginningAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
- {
- long actualSize;
- DescType actualType;
- OSErr status = 0, recStatus = 0;
- SRRecognizer rec;
-
- /* Get status */
- status = AEGetParamPtr(theAEevt,keySRSpeechStatus,typeShortInteger,
- &actualType, (Ptr)&recStatus, sizeof(status), &actualSize);
-
- /* Get SRRecognizer */
- if (!status && !recStatus)
- status = AEGetParamPtr(theAEevt,keySRRecognizer,typeSRRecognizer,
- &actualType, (Ptr)&rec, sizeof(SRRecognizer), &actualSize);
-
- /* Tell SRRecognizer to proceed with recognition attempt */
- if (!status && !recStatus && rec)
- SRContinueRecognition (rec);
- }
-
- #endif /* __USE_CALLBACKS__ */
-
- /*****************************************************************************/
-
- void ProcessResult (OSErr origStatus, SRRecognitionResult recResult)
- {
- OSErr status = origStatus;
- Str255 str;
- Size len;
- SRLanguageModel resultLM, subLM;
- unsigned long refCon;
-
- if (!status && recResult) {
- len = sizeof(resultLM);
- status = SRGetProperty (recResult, kSRLanguageModelFormat, &resultLM, &len);
- if (!status) {
- len = sizeof(refCon);
- status = SRGetProperty (resultLM, kSRRefCon, &refCon, &len);
- // if it's a valid result form our top-level LM,
- // then parse and process its elements
- if (!status && refCon == kTopLMRefCon) {
- // TopLM should have one sub element
- status = SRGetIndexedItem (resultLM, &subLM, 0);
- if (!status) {
- len = sizeof(refCon);
- status = SRGetProperty (subLM, kSRRefCon, &refCon, &len);
- if (!status) {
- // if subLM is from speakable items unit,
- // pass it on to that unit to handle it
- if (refCon == kSIModelRefCon)
- SIProcessResult (subLM);
-
- // else if it's our "quit speakable items" item, quit
- // (alternatively, we could another routine to parse
- // subLM, just like we call SIProcessResult above, to
- // handle the quit sub-item and any other sub-items)
- else if (refCon == kQuitSpeakableItems) {
- gFinished = true;
- #ifdef __HAS_UI__
- DisplayString ("\pGoodbye.");
- #endif
- SpeakString ("\pGoodbye.");
- }
-
- else if (refCon == kWhatTimeIsIt)
- SayDateOrTime (false);
-
- else if (refCon == kWhatDayIsIt)
- SayDateOrTime (true);
- }
-
- // release subelement when done with it
- SRReleaseObject (subLM);
- }
- }
-
- // release resultLM fetched above when done with it
- SRReleaseObject (resultLM);
- }
- }
-
- #ifdef __HAS_UI__
- // display error conditions
- if (status == kSRRecognitionDone)
- // no problem. recognizer just didn't recognize
- // one of the phrases for which we were listening.
- DisplayString ("\p...");
-
- else if (status == kSROutOfMemory)
- // ouch! we don't have enough free (system heap) memory to process
- // the utterence. speech recognition will not work until more memory
- // is available. it might make sense to set gFinished to true to quit,
- // since we can't do anything (or at least notify the user what to do)
- DisplayString ("\pOut of system memory.");
- else if (status)
- DisplayString ("\pRecognition error");
- #endif
-
-
- // Release SRRecognitionResult since we are done with it!!!
- // The toolbox has given us a reference to this object, and
- // assumes we are still using it until we call SRReleaseObject
- // with it.
- if (!origStatus) SRReleaseObject (recResult);
-
- }
-
- /*****************************************************************************/
-
- void SayDateOrTime (Boolean date)
- {
- unsigned long secs;
- Str255 str;
-
- GetDateTime(&secs);
- if (!date)
- IUTimeString(secs, false, str);
- else
- IUDateString(secs, longDate, str);
-
- #ifdef __HAS_UI__
- // Display string
- DisplayString (str);
- #endif
-
- // Call text-to-speech routine to have speech synthesizer speak string
- SpeakString (str);
- }
-
- /*****************************************************************************/
- #ifdef __HAS_UI__
- void DisplayString (Str255 str)
- {
- GrafPtr oldPort;
- Rect theRect;
-
- memcpy (gLastStr, str, str[0]+1);
- GetPort (&oldPort);
- SetPort (gDialog);
- theRect = ((GrafPtr)gDialog)->portRect;
- theRect.bottom = theRect.bottom-30;
- EraseRect(&theRect);
- TextSize (12);
- MoveTo (40,30);
- DrawString (str);
- SetPort (oldPort);
- }
- #endif
-
- /*****************************************************************************/
-